package com.im.netty.handler;

import com.alibaba.fastjson.JSON;
import com.im.model.SocketRequest;
import com.im.netty.group.ChannelGroup;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Component
@ChannelHandler.Sharable
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {


    @Autowired
    ChannelGroup channelGroup;

    Map<String,Channel>map = new HashMap<>();

    private static String WEBSOCKET_PATH = "/websocket";


    private WebSocketServerHandshaker handshaker;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        map.put(ctx.channel().id().asLongText(),ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        map.remove(ctx.channel().id().asLongText());
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest){
            handlerHttpRequest(channelHandlerContext,(FullHttpRequest)msg);
        }
        if (msg instanceof WebSocketFrame){
            handlerWebSocketFrame(channelHandlerContext,(WebSocketFrame)msg);
        }
    }

    private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {

        if (frame instanceof CloseWebSocketFrame){
            handshaker.close(ctx.channel(),(CloseWebSocketFrame)frame.retain());
        }
        if (frame instanceof PingWebSocketFrame){
            ctx.writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
        }
        if (frame instanceof TextWebSocketFrame){
            String text = ((TextWebSocketFrame) frame).text();
            System.out.println(ctx.name() + "\t" +text);
            SocketRequest socketRequest = JSON.parseObject(text, SocketRequest.class);
            switch (socketRequest.getTo().getType()){
                case "friend":
                    //私聊
                    channelGroup.handlerPrivateChat(socketRequest,ctx.channel());
                    break;
                case "group":
                    channelGroup.handlerGroupsChat(socketRequest,ctx.channel());
                    break;
                case "register":
                    channelGroup.registerUser(socketRequest.getMine().getId(),ctx.channel());
                    break;
                default:
                    break;
            }
//            Collection<Channel> values = map.values();
//            for (Channel value : values) {
////                value.writeAndFlush(new TextWebSocketFrame(((TextWebSocketFrame)frame).text()));
////                ByteBuf hello_world = Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8);
////                TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(hello_world);
////                value.writeAndFlush(textWebSocketFrame);
//                channelGroup.sendMsg(ctx.channel(),"hello world");
//            }
//            return;
        }
        if (frame instanceof BinaryWebSocketFrame){
            ctx.writeAndFlush(frame.retain());
        }

    }

    private void handlerHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {

        if (!req.decoderResult().isSuccess()){
            sendHttpReponse(ctx,req,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN));
            return;
        }
        if (req.method()!=HttpMethod.GET){
            sendHttpReponse(ctx,req,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.FORBIDDEN));
        }

        WebSocketServerHandshakerFactory wsFactory =
                new WebSocketServerHandshakerFactory(getWebSocketLocation(req),
                        null, true, 5 * 1024 * 1024);
        handshaker = wsFactory.newHandshaker(req);
        if (handshaker==null){
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        }else {
            handshaker.handshake(ctx.channel(),req);
        }

    }

    private String getWebSocketLocation(FullHttpRequest req) {
        String path = req.headers().get(HttpHeaderNames.HOST) + WEBSOCKET_PATH;
        return "ws://" + path;

    }

    private void sendHttpReponse(ChannelHandlerContext ctx, FullHttpRequest req,
                                 DefaultFullHttpResponse res) {

        if (res.status().code()!= HttpResponseStatus.OK.code()){
            ByteBuf byteBuf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
            res.content().writeBytes(byteBuf);
            byteBuf.release();
            HttpUtil.setContentLength(res,res.content().readableBytes());
        }
        ChannelFuture channelFuture = ctx.channel().writeAndFlush(res);
        if (!HttpUtil.isKeepAlive(req)||res.status().code()!=HttpResponseStatus.OK.code()){
            channelFuture.addListener(ChannelFutureListener.CLOSE);
        }
    }
}
